﻿using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using SIE.SCADA.Common.Log;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace SIE.SCADA.ZemtDemo.Common
{
    /// <summary>
    /// RabbitMQ 帮助类
    /// </summary>
    public class RabbitMQHelper
    {
        //private ConnectionFactory factory;
        public string HostName = Env.MQ_HostName.Value;
        public string UserName = Env.MQ_UserName.Value;
        public string Password = Env.MQ_Password.Value;
        public string VirtualHost = Env.MQ_VirtualHost.Value;
        public string Port = Env.MQ_Port.Value;

        /// <summary>
        /// 路由名称
        /// </summary>
        const string TopExchangeName = "topic.smdc.mes.exchange";
        /// <summary>
        /// 队列名称
        /// </summary>
        const string TopQueueName = "topic.smdc.mes.queue";

        private ConnectionFactory CreateConnectionFactory(string hostName = "", string userName = "", string password = "", string virtualHost = "", string port = "")
        {
            if (!string.IsNullOrEmpty(hostName)) HostName = hostName;
            if (!string.IsNullOrEmpty(userName)) UserName = userName;
            if (!string.IsNullOrEmpty(password)) Password = password;
            if (!string.IsNullOrEmpty(virtualHost)) VirtualHost = virtualHost;
            if (!string.IsNullOrEmpty(port)) Port = port;

            var factory = new ConnectionFactory()
            {
                HostName = HostName,
                UserName = UserName,
                Password = Password,
                VirtualHost = VirtualHost,
                Port = Convert.ToInt32(Port),
                Protocol = Protocols.DefaultProtocol

            };
            Logger.Info("HostName:" + HostName + "    UserName:" + UserName + "     Password:" + Password + "      VirtualHost:" + VirtualHost);
            factory.AutomaticRecoveryEnabled = true;
            //factory.ContinuationTimeout = new TimeSpan(0, 0, 5);
            return factory;
        }


        /// <summary>
        /// topic 模糊匹配模式，符号“#”匹配一个或多个词，符号“*”匹配不多不少一个词。因此“log.#”能够匹配到“log.info.oa”，但是“log.*” 只会匹配到“log.error”
        /// </summary>
        /// <param name="data">要发送的数据</param>
        /// <param name="topExchangeName">路由名称，默认：topic.smdc.mes.exchange</param>
        /// <param name="topQueueName">队列名称，默认：topic.smdc.mes.queue</param>
        public Result TopicExchangePublish(object data, string topExchangeName = "", string topQueueName = "",  string routingKey = "",
            bool exchangeDura = false,
            bool exchangeAutoDel = false,
            bool queueDura = false,
            bool queueAutoDel = false)
        {
            try
            {
                var factory = CreateConnectionFactory();
                topExchangeName = string.IsNullOrEmpty(topExchangeName) ? TopExchangeName : topExchangeName;
                //topQueueName = string.IsNullOrEmpty(topQueueName) ? TopQueueName : topQueueName;

                using (IConnection conn = factory.CreateConnection())
                {
                    using (IModel channel = conn.CreateModel())
                    {
                        channel.ExchangeDeclare(topExchangeName, ExchangeType.Topic, durable: exchangeDura, autoDelete: exchangeAutoDel, arguments: null);
                        if (!string.IsNullOrWhiteSpace(topQueueName))
                        {
                            channel.QueueDeclare(topQueueName, durable: queueDura, autoDelete: queueAutoDel, exclusive: false, arguments: null);
                            channel.QueueBind(topQueueName, topExchangeName, routingKey);
                        }
                        var props = channel.CreateBasicProperties();
                        props.AppId = "SIE";
                        props.MessageId = Guid.NewGuid().ToString();
                        //props.Persistent = true;
                        var jsonData = JsonConvert.SerializeObject(data);
                        
                        Logger.Info(jsonData);
                        var msgBody = Encoding.UTF8.GetBytes(jsonData);
                        channel.BasicPublish(exchange: topExchangeName, routingKey, props, body: msgBody);
                        Logger.Info(string.Format("==============TopicExchangePublish: {0},{1},{2}==============", topQueueName, topExchangeName, routingKey));
                        Logger.Info("==============TopicExchangePublish===========MessageId(发送):" + props.MessageId + "================");

                    }
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLine($"消息推送异常：{ex.Message}");
                return new Result(false, ex.Message);
            }
            return new Result(true);
        }


        IConnection conn = null;
        IModel channel = null;
        EventingBasicConsumer consumer = null;

        /// <summary>
        /// topic 模糊匹配模式，符号“#”匹配一个或多个词，符号“*”匹配不多不少一个词。因此“log.#”能够匹配到“log.info.oa”，但是“log.*” 只会匹配到“log.error”
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="funReceived">接收后回调</param>
        /// <param name="topExchangeName">路由名称，默认：topic.smdc.mes.exchange</param>
        /// <param name="topQueueName">队列名称，默认：topic.smdc.mes.queue</param>
        /// <returns></returns>
        public Result TopicExchangeConsumer<T>(Func<T, bool> funReceived, string topExchangeName = "", string topQueueName = "", string routingKey = "",
            bool exchangeDura = false,
            bool exchangeAutoDel = false,
            bool queueDura = false,
            bool queueAutoDel = false)
        {
            if (consumer != null && consumer.IsRunning)
            {
                //throw new Exception("消费监听正在运行！");
                Logger.Info("==============TopicExchangeConsumer Is Running ！==============" + DateTime.Now + topExchangeName);
                //System.Diagnostics.Trace.Fail("==============TopicExchangeConsumer Is Running ！=============="+DateTime.Now + topExchangeName);
                return new Result(false, "消费监听正在运行！"); 
            }
            try
            {
                var factory = CreateConnectionFactory();
                topExchangeName = string.IsNullOrEmpty(topExchangeName) ? TopExchangeName : topExchangeName;
                topQueueName = string.IsNullOrEmpty(topQueueName) ? TopQueueName : topQueueName;
                conn = factory.CreateConnection();
                channel = conn.CreateModel();

                channel.ExchangeDeclare(topExchangeName, ExchangeType.Topic, durable: exchangeDura, autoDelete: exchangeAutoDel, arguments: null);

                channel.QueueDeclare(topQueueName, durable: queueDura, autoDelete: queueAutoDel, exclusive: false, arguments: null);
               
                //channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
                channel.QueueBind(topQueueName, topExchangeName, routingKey);
                consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    try
                    {
                        Logger.Info(string.Format("==============TopicExchangeConsumer: {0}, {1}，{2}==============", topQueueName, topExchangeName, routingKey));
                        string messageid = ea.BasicProperties.MessageId;
                        Logger.Info("==============TopicExchangeConsumer============MessageId（接收）=====================" + messageid);
                        Logger.Info("==============TopicExchangeConsumer============ea==========" + ea + "===========");
                        Logger.Info("==============TopicExchangeConsumer============ea.Body==========" + ea.Body + "===========");
                        channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);


                        var msgBody = Encoding.UTF8.GetString(ea.Body);
                        
                        Logger.Info(msgBody);
                        
                        if (msgBody.Contains("\\")) msgBody = msgBody.Replace("\\", @"$");
                        msgBody = Regex.Replace(msgBody, @"(\\[^bfrnt\\/'\""])", "\\$1");
                        var data = JsonConvert.DeserializeObject<T>(msgBody);
                        
                        funReceived.Invoke(data);                                             
                        
                    }
                    catch (Exception ex)
                    {
                        Logger.Warn(ex.Message);
                        //LoggerHelper.Logger.CreatLogger("Service").Error(ex);
                        //throw;
                    }
                };
                channel.BasicConsume(topQueueName, false, consumer: consumer);
                //Logger.Info("==============TopicExchangeConsumer Start Running ！==============");

                return new Result(true);

            }
            catch (Exception ex)
            {
                return new Result(false, ex.Message);
            }
            finally
            {
                //if (channel != null) channel.Close();
                //if (conn != null) conn.Close();
            }
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        public void Close()
        {
            try
            {
                if (channel != null || conn != null)
                {
                    channel?.Close();
                    conn?.Close();
                    Logger.Info("==============TopicExchangeConsumer Is Closed ！==============");
                }
            }
            catch (Exception ex)
            {
                Logger.Warn($"消息推送异常：{ex.Message}");
                // return new Result(false, ex.Message);
            }

        }
    }
}
